/**
 * Copyright (c) 2024-2025 National Fundamental Software of China Co., Ltd.
 *
 * You should have find a copy of NFSChina License. If not, please contact us
 * by email <os_support@nfschina>
 *
**/

/*
    kcmmisc.cpp

    SPDX-FileCopyrightText: 1997 Patrick Dowler <dowler@morgul.fsh.uvic.ca>

    Layout management, cleanups:
    SPDX-FileCopyrightText: 1999 Dirk A. Mueller <dmuell@gmx.net>

    SPDX-FileCopyrightText: 2021 Cyril Rossi <cyril.rossi@enioka.com>

    SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "kcmmisc.h"
#include "qpainter.h"
#include "ui_kcmmiscwidget.h"
#include "keyboardmiscsettings.h"
#include "kcm_view_models.h"
#include "xkb_rules.h"
#include "flags.h"
#include "tastenbrett.h"
#include "kcm_add_layout_dialog.h"
#include "bindings.h"
#include "KWindowSystem/kwindowsystem.h"
#include "xkb_helper.h"
#include "keyboardsettings.h"

#include <QButtonGroup>
#include <QCheckBox>
#include <QDoubleSpinBox>
#include <QSpinBox>
#include <QWhatsThis>
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
#include <QX11Info>
#else
#include <QtGui/private/qtx11extras_p.h>
#endif

#include <KConfig>
#include <KConfigGroup>
#include <KLocalizedString>
#include <KSharedConfig>
#include <KColorScheme>
#include <X11/Xlib.h>
#include <cmath>
#include <QStyledItemDelegate>
#include <QListView>
#include <QStandardItemModel>
#include <QPainter>
#include <QComboBox>
#include <QProcess>

static const QString GROUP_SWITCH_GROUP_NAME(QStringLiteral("grp"));
static const QString LV3_SWITCH_GROUP_NAME(QStringLiteral("lv3"));

static const int TAB_HARDWARE = 0;
static const int TAB_LAYOUTS = 1;
static const int TAB_ADVANCED = 2;

static const int MIN_LOOPING_COUNT = 2;

namespace
{
bool hasAccentSupport()
{
    static bool isPlasmaIM = (qgetenv("QT_IM_MODULE") == "plasmaim");
    return isPlasmaIM;
}
}

class KeyboardLayoutDelegate : public QStyledItemDelegate {
    Q_OBJECT

public:
    KeyboardLayoutDelegate(QObject *parent = nullptr) : QStyledItemDelegate(parent) {}

    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override {
        QStyleOptionViewItem opt = option;
        initStyleOption(&opt, index);

        // Draw the background
        if (index.data(Qt::UserRole + 1).toBool()) { // isLoopingLayout
            opt.backgroundBrush = QBrush(QColor(240, 240, 240)); // Gray background
        }

        painter->save();
        painter->setRenderHint(QPainter::Antialiasing);
        QApplication::style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter);
        painter->restore();

        // Draw the icon, title, subtitle, and shortcut
        QRect iconRect = opt.rect;
        iconRect.setWidth(32); // Example icon size
        QIcon icon = QIcon::fromTheme(index.data(Qt::UserRole + 2).toString()); // layout icon
        icon.paint(painter, iconRect);

        QRect textRect = opt.rect;
        textRect.setLeft(iconRect.right() + 8); // Spacing between icon and text

        QString layoutName = index.data(Qt::DisplayRole).toString();
        QString variantName = index.data(Qt::UserRole + 3).toString();
        QString shortcut = index.data(Qt::UserRole + 4).toString();

        QFont font = painter->font();
        font.setBold(true);
        painter->setFont(font);
        painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, layoutName);

        font.setBold(false);
        font.setItalic(true);
        painter->setFont(font);
        textRect.setTop(textRect.bottom() + 4); // Spacing between title and subtitle
        painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, variantName);

        // Draw the shortcut (simplified, no actual QKeySequenceItem equivalent)
        textRect.setTop(textRect.bottom() + 4);
        painter->setFont(font);
        painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, shortcut);
    }

    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override {
        QSize size = QStyledItemDelegate::sizeHint(option, index);
        size.setHeight(size.height() * 3); // Example adjustment for multiple lines
        return size;
    }
};

static bool xkbOptionGroupLessThan(const OptionGroupInfo *og1, const OptionGroupInfo *og2)
{
    return og1->description.toLower() < og2->description.toLower();
}
static bool xkbOptionLessThan(const OptionInfo *o1, const OptionInfo *o2)
{
    return o1->description.toLower() < o2->description.toLower();
}

KCMiscKeyboardWidget::KCMiscKeyboardWidget(QWidget *parent, KeyboardMiscSettings *settings)
    : QWidget(parent)
    , ui(*new Ui_KeyboardConfigWidget)
    , m_settings(settings)
{
    ui.setupUi(this);

    //rules = new Rules();
    rules = Rules::readRules(Rules::READ_EXTRAS);
    flags = new Flags();
    keyboardConfig = new KeyboardConfig(this);
    m_layoutSettings = new KeyboardSettingsBase(this);
    actionCollection = nullptr;

    auto config = KSharedConfig::openConfig();
    auto active = KColorScheme(QPalette::Active, KColorScheme::View, config);
    QColor thisbackground = active.background(KColorScheme::NormalBackground).color();
    QColor thisbox = active.background().color();
    QString thisbackgroundstr = QString("rgb(%1, %2, %3)").arg(thisbackground.red()).arg(thisbackground.green()).arg(thisbackground.blue());
    QString boxcolor = QString("rgb(%1, %2, %3)").arg(thisbox.red()).arg(thisbox.green()).arg(thisbox.blue());
    QString themeborder=thisbackgroundstr=="rgb(255, 255, 255)"?"rgb(204, 204, 204)":"rgb(45, 45, 45)";
    qDebug()<<boxcolor<<thisbackgroundstr;

    ui.label_4->hide();
    ui.keyboardModelComboBox->hide();
    ui.kcfg_resetOldXkbOptions->hide();
    ui.xkbOptionsTreeView->hide();

    uiUpdating = false;
    ui.moveUpBtn->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up")));
    ui.moveDownBtn->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down")));
    ui.addLayoutBtn->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
    ui.removeLayoutBtn->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));

    //初始化tree ui界面
    std::sort(rules->optionGroupInfos.begin(), rules->optionGroupInfos.end(), xkbOptionGroupLessThan);
    for (OptionGroupInfo *optionGroupInfo : qAsConst(rules->optionGroupInfos)) {
        std::sort(optionGroupInfo->optionInfos.begin(), optionGroupInfo->optionInfos.end(), xkbOptionLessThan);
    }
    XkbOptionsTreeModel *model = new XkbOptionsTreeModel(rules, ui.xkbOptionsTreeView);
    ui.xkbOptionsTreeView->setModel(model);
    connect(model, &QAbstractItemModel::dataChanged, this, &KCMiscKeyboardWidget::uiChanged);

    connect(ui.kcfg_resetOldXkbOptions, &QAbstractButton::toggled, this, &KCMiscKeyboardWidget::configureXkbOptionsChanged);
    connect(ui.kcfg_resetOldXkbOptions, &QAbstractButton::toggled, ui.xkbOptionsTreeView, &QWidget::setEnabled);
    //初始化combox ui界面
    for (const ModelInfo *modelInfo : qAsConst(rules->modelInfos)) {
        QString vendor = modelInfo->vendor;
        if (vendor.isEmpty()) {
            vendor = i18nc("unknown keyboard model vendor", "Unknown");
        }
        ui.keyboardModelComboBox->addItem(i18nc("vendor | keyboard model", "%1 | %2", vendor, modelInfo->description), modelInfo->name);
    }
    ui.keyboardModelComboBox->model()->sort(0);
    connect(ui.keyboardModelComboBox, SIGNAL(activated(int)), this, SLOT(uiChanged()));
    connect(ui.keyboardModelComboBox, qOverload<int>(&QComboBox::currentIndexChanged), this, &KCMiscKeyboardWidget::updateUiDefaultIndicator);

    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

    layoutsTableModel = new LayoutsTableModel(rules, flags, keyboardConfig, ui.layoutsTableView);
    ui.layoutsTableView->setEditTriggers(QAbstractItemView::SelectedClicked | QAbstractItemView::DoubleClicked | QAbstractItemView::EditKeyPressed
                                                | QAbstractItemView::AnyKeyPressed);
    ui.layoutsTableView->setModel(layoutsTableModel);
    layoutsTableModel->refresh();
    ui.layoutsTableView->resizeRowsToContents();
    //ui.layoutsTableView->setModel(layoutsTableModel);
    ui.layoutsTableView->setIconSize({22, 22});
    // TODO: do we need to delete this delegate or parent will take care of it?
    VariantComboDelegate *variantDelegate = new VariantComboDelegate(keyboardConfig, rules, ui.layoutsTableView);
    ui.layoutsTableView->setItemDelegateForColumn(LayoutsTableModel::VARIANT_COLUMN, variantDelegate);
    LabelEditDelegate *labelDelegate = new LabelEditDelegate(keyboardConfig, ui.layoutsTableView);
    ui.layoutsTableView->setItemDelegateForColumn(LayoutsTableModel::DISPLAY_NAME_COLUMN, labelDelegate);
    KKeySequenceWidgetDelegate *shortcutDelegate = new KKeySequenceWidgetDelegate(keyboardConfig, ui.layoutsTableView);
    ui.layoutsTableView->setItemDelegateForColumn(LayoutsTableModel::SHORTCUT_COLUMN, shortcutDelegate);
    // TODO: is it ok to hardcode sizes? any better approach?
    ui.layoutsTableView->setColumnWidth(LayoutsTableModel::MAP_COLUMN, 70);
    ui.layoutsTableView->setColumnWidth(LayoutsTableModel::LAYOUT_COLUMN, 190);
    ui.layoutsTableView->setColumnWidth(LayoutsTableModel::VARIANT_COLUMN, 180);
    ui.layoutsTableView->setColumnWidth(LayoutsTableModel::DISPLAY_NAME_COLUMN, 50);
    ui.layoutsTableView->setColumnWidth(LayoutsTableModel::SHORTCUT_COLUMN, 95);
    connect(layoutsTableModel, &LayoutsTableModel::dataChanged, this, [this]() {
        Q_EMIT changed(true);
    });
    connect(ui.addLayoutBtn, &QAbstractButton::clicked, this, &KCMiscKeyboardWidget::addLayout);
    connect(ui.removeLayoutBtn, &QAbstractButton::clicked, this, &KCMiscKeyboardWidget::removeLayout);
    connect(ui.layoutsTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &KCMiscKeyboardWidget::layoutSelectionChanged);
    connect(ui.layoutsTableView->model(), qOverload<const QModelIndex &, const QModelIndex &, const QVector<int> &>(&QAbstractItemModel::dataChanged),
            this, &KCMiscKeyboardWidget::uiChanged);
    connect(ui.moveUpBtn, &QAbstractButton::clicked, this, &KCMiscKeyboardWidget::moveUp);
    connect(ui.moveDownBtn, &QAbstractButton::clicked, this, &KCMiscKeyboardWidget::moveDown);
    connect(ui.previewButton, &QAbstractButton::clicked, this, &KCMiscKeyboardWidget::previewLayout);

    connect(ui.kcfg_configureLayouts, &QGroupBox::toggled, this, &KCMiscKeyboardWidget::configureLayoutsChanged);

    QSizePolicy sizePolicy = ui.keyboardRepeatParamsGroupBox->sizePolicy();
    sizePolicy.setHorizontalPolicy(QSizePolicy::Fixed); // 水平方向固定
    sizePolicy.setVerticalPolicy(QSizePolicy::Preferred); // 垂直方向保持默认
    ui.keyboardRepeatParamsGroupBox->setSizePolicy(sizePolicy);
    ui.keyboardRepeatParamsGroupBox->setFixedWidth(558);

    ui.kcfg_repeatDelay->setSingleStep(50);
    ui.kcfg_repeatRate->setSingleStep(5);

    sliderMax = (int)floor(0.5 + 2 * (log(5000.0L) - log(100.0L)) / (log(5000.0L) - log(4999.0L)));
    ui.delaySlider->setRange(0, sliderMax);
    ui.delaySlider->setSingleStep(sliderMax / 100);
    ui.delaySlider->setPageStep(sliderMax / 10);
    ui.delaySlider->setTickInterval(sliderMax / 10);

    ui.rateSlider->setRange(20, 10000);
    ui.rateSlider->setSingleStep(30);
    ui.rateSlider->setPageStep(500);
    ui.rateSlider->setTickInterval(498);


    ui.keyboardRepeatParamsGroupBox->setStyleSheet(QString("QGroupBox#keyboardRepeatParamsGroupBox{\
                                                        background-color:%1;\
                                                       border-radius:10px;\
                                                       border: 1px  solid %2;\
                                                       }").arg(thisbackgroundstr).arg(themeborder));
    ui.TestareaGroupBox->setStyleSheet(QString("QGroupBox#TestareaGroupBox{\
                                                        background-color:%1;\
                                                       border-radius:10px;\
                                                       border: 1px  solid %2;\
                                                       }").arg(thisbackgroundstr).arg(themeborder));


    ui.keyPressStatusComboBox->setStyleSheet(QString("background-color:%1;").arg(boxcolor));
    ui.kcfg_repeatDelay->setStyleSheet(QString("background-color:%1;").arg(boxcolor));
    ui.kcfg_repeatRate->setStyleSheet(QString("background-color:%1;").arg(boxcolor));
    ui.lineEdit->setStyleSheet(QString("background-color:%1;").arg(boxcolor));


    connect(ui.kcfg_repeatDelay, SIGNAL(valueChanged(int)), this, SLOT(delaySpinboxChanged(int)));
    connect(ui.delaySlider, &QAbstractSlider::valueChanged, this, &KCMiscKeyboardWidget::delaySliderChanged);
    connect(ui.kcfg_repeatRate, SIGNAL(valueChanged(double)), this, SLOT(rateSpinboxChanged(double)));
    connect(ui.rateSlider, &QAbstractSlider::valueChanged, this, &KCMiscKeyboardWidget::rateSliderChanged);
    

    _numlockButtonGroup = new QButtonGroup(ui.numlockButtonGroup);
    _numlockButtonGroup->addButton(ui.radioButton1, 0);
    _numlockButtonGroup->addButton(ui.radioButton2, 1);
    _numlockButtonGroup->addButton(ui.radioButton3, 2);

    connect(_numlockButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(changed()));

    _keyboardRepeatButtonGroup = new QButtonGroup(ui.repeatFormLayout);
    if (hasAccentSupport()) {
        _keyboardRepeatButtonGroup->addButton(ui.accentMenuRadioButton, 0);
    } else {
        ui.accentMenuRadioButton->setVisible(false);
    }
    _keyboardRepeatButtonGroup->addButton(ui.accentMenuRadioButton, 0);
    _keyboardRepeatButtonGroup->addButton(ui.repeatRadioButton, 1);
    _keyboardRepeatButtonGroup->addButton(ui.nothingRadioButton, 2);

    connect(_keyboardRepeatButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(changed()));
    connect(_keyboardRepeatButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(keyboardRepeatStateChanged(int)));

    //connect(ui.keyPressStatusComboBox, SIGNAL(currentIndexChanged(int)), _keyboardRepeatButtonGroup, SLOT(buttonClicked(int)));
    connect(ui.keyPressStatusComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changeVale(int)));


    connect(_numlockButtonGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked),
            this, &KCMiscKeyboardWidget::updateUiDefaultIndicator);
    connect(_keyboardRepeatButtonGroup, qOverload<QAbstractButton *>(&QButtonGroup::buttonClicked),
            this, &KCMiscKeyboardWidget::updateUiDefaultIndicator);

    ui.numlockGroupBox->hide();
    ui.label_2->hide();
    ui.repeatRadioButton->hide();
    ui.nothingRadioButton->hide();
    ui.nothingRadioButton->hide();
}

KCMiscKeyboardWidget::~KCMiscKeyboardWidget()
{
    delete flags;
    //delete rules;
    delete &ui;
}

void KCMiscKeyboardWidget::configureLayoutsChanged()
{
    if (ui.kcfg_configureLayouts->isChecked() && keyboardConfig->layouts.isEmpty()) {
        populateWithCurrentLayouts();
    } else {
        keyboardConfig->layouts.clear();
    }
    uiChanged();
}

void KCMiscKeyboardWidget::populateWithCurrentLayouts()
{
    const QList<LayoutUnit> layouts = X11Helper::getLayoutsList();
    for (const auto &layoutUnit : layouts) {
        if(layoutUnit.isEmpty())
        {
            continue;
        }
        else
        {
            qDebug() << layoutUnit.toString();
        }
        keyboardConfig->layouts.append(layoutUnit);
    }
}

void KCMiscKeyboardWidget::scrollToGroupShortcut()
{
    ui.keyboardModelComboBox->setCurrentIndex(TAB_ADVANCED);
    if (!ui.kcfg_resetOldXkbOptions->isChecked()) {
        ui.kcfg_resetOldXkbOptions->setChecked(true);
    }
    ((XkbOptionsTreeModel *)ui.xkbOptionsTreeView->model())->gotoGroup(GROUP_SWITCH_GROUP_NAME, ui.xkbOptionsTreeView);
}

void KCMiscKeyboardWidget::scrollTo3rdLevelShortcut()
{
    ui.keyboardModelComboBox->setCurrentIndex(TAB_ADVANCED);
    if (!ui.kcfg_resetOldXkbOptions->isChecked()) {
        ui.kcfg_resetOldXkbOptions->setChecked(true);
    }
    ((XkbOptionsTreeModel *)ui.xkbOptionsTreeView->model())->gotoGroup(LV3_SWITCH_GROUP_NAME, ui.xkbOptionsTreeView);
}

// set the slider and LCD values
void KCMiscKeyboardWidget::setRepeat(KeyBehaviour keyboardRepeat, int delay_, double rate_)
{
    _keyboardRepeatButtonGroup->button(keyboardRepeat)->click();
    ui.keyPressStatusComboBox->setCurrentIndex(keyboardRepeat-1);
    delaySpinboxChanged(delay_);
    rateSpinboxChanged(rate_);
}

TriState TriStateHelper::getTriState(const QButtonGroup *group)
{
    int selected = group->checkedId();
    return selected < 0 ? STATE_UNCHANGED : getTriState(selected);
}

void TriStateHelper::setTriState(QButtonGroup *group, TriState state)
{
    group->button(getInt(state))->click();
}

void KCMiscKeyboardWidget::load()
{
    // 读取键盘重复设置
    QString key = m_settings->keyboardRepeat();
    if (key == QLatin1String("true") || key == TriStateHelper::getString(STATE_ON) || key == QLatin1String("accent")) {
        keyboardRepeat = KeyBehaviour::AccentMenu;
    } else if (key == QLatin1String("false") || key == TriStateHelper::getString(STATE_OFF) || key == QLatin1String("nothing")) {
        keyboardRepeat = KeyBehaviour::DoNothing;
    } else if (key == QLatin1String("repeat")) {
        keyboardRepeat = KeyBehaviour::RepeatKey;
    }
    setRepeat(keyboardRepeat, m_settings->repeatDelay(), m_settings->repeatRate());

    // 读取 NumLock 设置
    numlockState = TriStateHelper::getTriState(m_settings->numLock());
    TriStateHelper::setTriState(_numlockButtonGroup, numlockState);

    // 加载布局列表
   ui.layoutsTableView->setModel(layoutsTableModel);
   //QStringList layoutList = m_layoutSettings->layoutList();

   KConfigGroup group(m_layoutSettings->config(), "Layout");
   QStringList layoutList = group.readEntry("LayoutList", QStringList());

   qDebug() << "Loading layout list:" << layoutList;

   keyboardConfig->layouts.clear();
   if(layoutList.isEmpty())
   {
       return;
   }

   // 解析布局列表并添加到模型中
   for (const QString &layoutDescription : layoutList) {
       QStringList parts = layoutDescription.split(",");
       if (parts.size() < 5) { // 根据保存时的格式调整大小
           qWarning() << "Invalid layout description, skipping:" << layoutDescription;
           continue;
       }

       // 创建 LayoutUnit 对象并设置属性
       LayoutUnit layoutUnit(parts[0], parts[1], QKeySequence(parts[4].trimmed())); // 根据原来的构造函数设置快捷键
       layoutUnit.setVariant(parts[2].trimmed());
       layoutUnit.setDisplayName(parts[3].trimmed());

       // 将 LayoutUnit 对象添加到模型和配置中
       keyboardConfig->layouts.append(layoutUnit);
       //layoutsTableModel->addLayoutUnit(layoutUnit); // 假设模型有添加方法
       qDebug() << "Loaded layout description:" << layoutDescription;
   }

   layoutsTableModel->refresh();
   //ui.layoutsTableView->setModel(layoutsTableModel);
   ui.layoutsTableView->resizeRowsToContents();
}

void KCMiscKeyboardWidget::save()
{
    if (!rules)
        return;

    // 设置键盘模型
    keyboardConfig->setKeyboardModel(keyboardModelFromUI());

    // 保存 NumLock 设置
    numlockState = TriStateHelper::getTriState(_numlockButtonGroup);
    m_settings->setNumLock(TriStateHelper::getInt(numlockState));

    // 保存键盘重复设置
    keyboardRepeat = KeyBehaviour(_keyboardRepeatButtonGroup->checkedId());
    m_settings->setKeyboardRepeat(keybehaviourNames[keyboardRepeat]);

    // 保存重复延迟和速率
    m_settings->setRepeatDelay(ui.kcfg_repeatDelay->value());
    m_settings->setRepeatRate(ui.kcfg_repeatRate->value());

    // 刷新模型以应用更改
    layoutsTableModel->refresh();
    ui.layoutsTableView->resizeRowsToContents();
    uiChanged();

    QString maplist;
    QString variantlist;

    // 保存布局列表
    QStringList layoutList;
    QStringList variantList;
    QStringList displayNameList;
    QStringList mapList;
    QStringList shortCutList;
    const auto rowCount = layoutsTableModel->rowCount();
    for (int row = 0; row < rowCount; ++row) {
        // 从模型中获取 LayoutUnit 对象的属性
        const QModelIndex indexMap = layoutsTableModel->index(row, LayoutsTableModel::MAP_COLUMN);
        const QString map = layoutsTableModel->data(indexMap, Qt::DisplayRole).toString();
        qDebug() << "map" << map;

        const QModelIndex indexLayout = layoutsTableModel->index(row, LayoutsTableModel::LAYOUT_COLUMN);
        const QString layout = layoutsTableModel->data(indexLayout, Qt::DisplayRole).toString();
        qDebug() << "layout" << layout;

        const QModelIndex indexVariant = layoutsTableModel->index(row, LayoutsTableModel::VARIANT_COLUMN);
        QString variant = layoutsTableModel->data(indexVariant, Qt::DisplayRole).toString();
        qDebug() << "variant" << variant;

        const LayoutInfo *layoutInfo = rules->getLayoutInfo(map);
        if (!layoutInfo) {
            qDebug() << "layoutInfo is null";
            continue;
        }

        for (const VariantInfo *variantInfo : layoutInfo->variantInfos) {
            if (variant == variantInfo->description) {
                variant = variantInfo->name;
                qDebug() << variant;
                break;
            }
        }

        const QModelIndex indexDisplayName = layoutsTableModel->index(row, LayoutsTableModel::DISPLAY_NAME_COLUMN);
        const QString displayName = layoutsTableModel->data(indexDisplayName, Qt::DisplayRole).toString();
        const QModelIndex indexShortcut = layoutsTableModel->index(row, LayoutsTableModel::SHORTCUT_COLUMN);
        const QString shortcut = layoutsTableModel->data(indexShortcut, Qt::DisplayRole).toString();

        layoutList.append(QString("%1,%2,%3,%4,%5").arg(map, layout, variant, displayName, shortcut));

        maplist +=  map;
        if(variant.isEmpty())
        {
            variantlist += " ";
            variantlist += ",";
        }
        else
        {
            variantlist += variant;
        }

        if(row < rowCount - 1)
        {
            if(!map.isEmpty())
            {
                maplist += ",";
            }
            if(!variant.isEmpty())
            {
                variantlist += ",";
            }
        }
    }

    qDebug() << "************************************************************" << maplist;
    qDebug() << "************************************************************" << variantlist;

    QStringList arguments;
    arguments << "-layout" << maplist << "-variant" << variantlist;
    XkbHelper xkbHelper;

   bool issuccess = xkbHelper.runConfigLayoutCommand(arguments);
   qDebug() << "save success";
//    // 更新保存的布局列表到设置中
    m_layoutSettings->setLayoutList(layoutList);
    m_layoutSettings->setVariantList(variantList);
    m_layoutSettings->setDisplayNames(variantList);
    m_layoutSettings->setMapNames(mapList);
    m_layoutSettings->setShortCuts(shortCutList);

    KConfigGroup group(m_layoutSettings->config(), "Layout");
    group.writeEntry("LayoutList", layoutList);
    m_layoutSettings->config()->sync();
    // 发出更改信号
    Q_EMIT changed(true);
    //Q_EMIT layoutListChanged();
}

void KCMiscKeyboardWidget::defaults()
{
    setRepeat(defaultValueKeyboardRepeat(), m_settings->defaultRepeatDelayValue(), m_settings->defaultRepeatRateValue());
    TriStateHelper::setTriState(_numlockButtonGroup, static_cast<TriState>(m_settings->defaultNumLockValue()));
    auto *xkbOptionModel = dynamic_cast<XkbOptionsTreeModel *>(ui.xkbOptionsTreeView->model());
    xkbOptionModel->setXkbOptions(keyboardConfig->defaultXkbOptionsValue());
    keyboardConfig->setDefaults();

    //默认先清理qstringlist然后再添加默认的us
    KConfigGroup group(m_layoutSettings->config(), "Layout");
    group.deleteEntry("LayoutList");
    m_layoutSettings->config()->sync();

    QStringList layoutList;
    layoutList.append(QString("'us','英语 (美国)','','',''"));
    //KConfigGroup group(m_layoutSettings->config(), "Layout");
    group.writeEntry("LayoutList", layoutList);
    m_layoutSettings->config()->sync();
    QStringList arguments;
    arguments << "-layout" << "us";
    XkbHelper xkbHelper;
    bool issuccess = xkbHelper.runConfigLayoutCommand(arguments);

    Q_EMIT changed(true);
}

QStringList KCMiscKeyboardWidget::getTableDataAsStringList(LayoutsTableModel *model) {
    QStringList dataList;
    int rowCount = model->rowCount();
    int columnCount = model->columnCount(QModelIndex());

    for (int row = 0; row < rowCount; ++row) {
        for (int column = 0; column < columnCount; ++column) {
            QModelIndex index = model->index(row, column);
            QVariant data = model->data(index, Qt::DisplayRole);
            if (data.isValid()) {
                dataList.append(data.toString());
            }
        }
    }

    return dataList;
}

QString KCMiscKeyboardWidget::quickHelp() const
{
    return QString();

    /* "<h1>Keyboard</h1> This module allows you to choose options"
       " for the way in which your keyboard works. The actual effect of"
       " setting these options depends upon the features provided by your"
       " keyboard hardware and the X server on which Plasma is running.<p>"
       " For example, you may find that changing the key click volume"
       " has no effect because this feature is not available on your system." */
}

bool KCMiscKeyboardWidget::isSaveNeeded() const
{
    return m_settings->keyboardRepeat() != keybehaviourNames[KeyBehaviour(_keyboardRepeatButtonGroup->checkedId())]
            || m_settings->numLock() != TriStateHelper::getInt(TriStateHelper::getTriState(_numlockButtonGroup))
            || keyboardModelFromTableView() != keyboardConfig->keyboardModel() ;
}

bool KCMiscKeyboardWidget::isDefault() const
{
    return defaultValueKeyboardRepeat() == KeyBehaviour(_keyboardRepeatButtonGroup->checkedId())
            && m_settings->defaultNumLockValue() == TriStateHelper::getInt(TriStateHelper::getTriState(_numlockButtonGroup));
}

void KCMiscKeyboardWidget::setDefaultIndicator(bool visible)
{
    m_highlightVisible = visible;
    updateUiDefaultIndicator();
}

QString KCMiscKeyboardWidget::keyboardModelFromTableView() const
{
    // 确保有一个当前选中的行
    QModelIndexList selectedRows = ui.layoutsTableView->selectionModel()->selectedRows();
    if (selectedRows.isEmpty()) {
        return QString(); // 或者返回一个默认值
    }

    // 获取当前选中行的特定列（假设是第二列，角色为 Qt::UserRole + 1）的索引
    QModelIndex index = selectedRows.first().sibling(selectedRows.first().row(), 1); // 假设是第二列（索引为1）

    // 从模型中检索数据
    QVariant data = ui.layoutsTableView->model()->data(index, Qt::UserRole + 1);

    // 将 QVariant 转换为 QString
    return data.toString();
}

void KCMiscKeyboardWidget::updateUiDefaultIndicator()
{
    const auto isNumLockDefault = m_settings->defaultNumLockValue() == TriStateHelper::getInt(TriStateHelper::getTriState(_numlockButtonGroup));
    for (auto button : _numlockButtonGroup->buttons()) {
        setDefaultIndicatorVisible(button, m_highlightVisible && !isNumLockDefault && _numlockButtonGroup->checkedButton() == button);
    }

    const auto isKeyboardRepeatDefault = defaultValueKeyboardRepeat() == KeyBehaviour(_keyboardRepeatButtonGroup->checkedId());
    for (auto button : _keyboardRepeatButtonGroup->buttons()) {
        setDefaultIndicatorVisible(button, m_highlightVisible && !isKeyboardRepeatDefault && _keyboardRepeatButtonGroup->checkedButton() == button);
    }

    setDefaultIndicatorVisible(ui.delaySlider, m_highlightVisible && ui.kcfg_repeatDelay->value() != m_settings->defaultRepeatDelayValue());
    setDefaultIndicatorVisible(ui.rateSlider, m_highlightVisible && ui.kcfg_repeatRate->value() != m_settings->defaultRepeatRateValue());
}

void KCMiscKeyboardWidget::updateHardwareUI(const QString &model)
{
    int idx = ui.keyboardModelComboBox->findData(model);
    if (idx != -1) {
        ui.keyboardModelComboBox->setCurrentIndex(idx);
    }
}

void KCMiscKeyboardWidget::delaySliderChanged(int value)
{
    double alpha = sliderMax / (log(5000.0L) - log(100.0L));
    double linearValue = exp(value / alpha + log(100.0L));

    ui.kcfg_repeatDelay->setValue((int)floor(0.5 + linearValue));
    updateUiDefaultIndicator();

    Q_EMIT changed(true);
}

void KCMiscKeyboardWidget::delaySpinboxChanged(int value)
{
    double alpha = sliderMax / (log(5000.0L) - log(100.0L));
    double logVal = alpha * (log((double)value) - log(100.0L));

    ui.delaySlider->setValue((int)floor(0.5 + logVal));

    Q_EMIT changed(true);
}

void KCMiscKeyboardWidget::rateSliderChanged(int value)
{
    ui.kcfg_repeatRate->setValue(value / 100.0);
    updateUiDefaultIndicator();

    Q_EMIT changed(true);
}

void KCMiscKeyboardWidget::rateSpinboxChanged(double value)
{
    ui.rateSlider->setValue((int)(value * 100));
    Q_EMIT changed(true);
}

void KCMiscKeyboardWidget::changed()
{
    Q_EMIT changed(true);
}

void KCMiscKeyboardWidget::changeVale(int num)
{
    if ( num == 0 )
    {
        _keyboardRepeatButtonGroup->button(num+1)->click();
        ui.label->show();
        ui.lineEdit->show();
        ui.lblDelay->show();
        ui.delaySlider->show();
        ui.kcfg_repeatDelay->show();
        ui.lblRate->show();
        ui.rateSlider->show();
        ui.kcfg_repeatRate->show();
        ui.line->show();
        ui.line_2->show();
        ui.TestareaGroupBox->show();
        ui.layoutsTableView->show();
    }
    else
    {
       _keyboardRepeatButtonGroup->button(num+1)->click();
       // ui.label->hide();
       // ui.lineEdit->hide();
        ui.lblDelay->hide();
        ui.delaySlider->hide();
        ui.kcfg_repeatDelay->hide();
        ui.lblRate->hide();
        ui.rateSlider->hide();
        ui.kcfg_repeatRate->hide();
        ui.line->hide();
        ui.line_2->hide();
        ui.layoutsTableView->show();
      // ui.TestareaGroupBox->hide();
    }
}

void KCMiscKeyboardWidget::keyboardRepeatStateChanged(int selection)
{
    //ui.keyboardRepeatParamsGroupBox->setVisible(selection == KeyBehaviour::RepeatKey);
    ui.lblDelay->setVisible(selection == KeyBehaviour::RepeatKey);
    ui.delaySlider->setVisible(selection == KeyBehaviour::RepeatKey);
    ui.kcfg_repeatDelay->setVisible(selection == KeyBehaviour::RepeatKey);
    ui.lblRate->setVisible(selection == KeyBehaviour::RepeatKey);
    ui.rateSlider->setVisible(selection == KeyBehaviour::RepeatKey);
    ui.kcfg_repeatRate->setVisible(selection == KeyBehaviour::RepeatKey);
    ui.line->setVisible(selection == KeyBehaviour::RepeatKey);
    ui.line_2->setVisible(selection == KeyBehaviour::RepeatKey);
    ui.layoutsTableView->setVisible(selection == KeyBehaviour::RepeatKey);
    changed();
}

static QPair<int, int> getSelectedRowRange(const QModelIndexList &selected)
{
    if (selected.isEmpty()) {
        return QPair<int, int>(-1, -1);
    }

    QList<int> rows;
    for (const auto &index : selected) {
        rows << index.row();
    }
    std::sort(rows.begin(), rows.end());
    return QPair<int, int>(rows[0], rows[rows.size() - 1]);
}

void KCMiscKeyboardWidget::addLayout()
{
    AddLayoutDialog dialog(rules,
                           flags,
                           keyboardModelFromUI(),
                           xkbOptionsFromUI(),
                           false,
                           this);
    dialog.setModal(true);
    if (dialog.exec() == QDialog::Accepted) {
        keyboardConfig->layouts.append(dialog.getSelectedLayoutUnit());
        layoutsTableModel->refresh();
        ui.layoutsTableView->resizeRowsToContents();
        uiChanged();
    }
    updateLoopCount();
}

void KCMiscKeyboardWidget::removeLayout()
{
    if (!ui.layoutsTableView->selectionModel()->hasSelection())
        return;

    const QModelIndexList selected = ui.layoutsTableView->selectionModel()->selectedIndexes();
    QPair<int, int> rowsRange(getSelectedRowRange(selected));
    for (const auto &idx : selected) {
        if (idx.column() == 0) {
            keyboardConfig->layouts.removeAt(rowsRange.first);
        }
    }
    layoutsTableModel->refresh();
    uiChanged();

    if (keyboardConfig->layouts.size() > 0) {
        int rowToSelect = rowsRange.first;
        if (rowToSelect >= keyboardConfig->layouts.size()) {
            rowToSelect--;
        }

        QModelIndex topLeft = layoutsTableModel->index(rowToSelect, 0, QModelIndex());
        QModelIndex bottomRight = layoutsTableModel->index(rowToSelect, layoutsTableModel->columnCount(topLeft) - 1, QModelIndex());
        QItemSelection selection(topLeft, bottomRight);
        ui.layoutsTableView->selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
        ui.layoutsTableView->setFocus();
    }

    layoutSelectionChanged();

    updateLoopCount();
}

void KCMiscKeyboardWidget::layoutSelectionChanged()
{
    QModelIndexList selected = ui.layoutsTableView->selectionModel()->selectedIndexes();
    ui.removeLayoutBtn->setEnabled(!selected.isEmpty());
    QPair<int, int> rowsRange(getSelectedRowRange(selected));
    ui.moveUpBtn->setEnabled(!selected.isEmpty() && rowsRange.first > 0);
    ui.previewButton->setEnabled(ui.layoutsTableView->selectionModel()->selectedRows().size() == 1);
    ui.previewButton->setVisible(Tastenbrett::exists());
    ui.moveDownBtn->setEnabled(!selected.isEmpty() && rowsRange.second < keyboardConfig->layouts.size() - 1);

    Q_EMIT changed(true);
}

void KCMiscKeyboardWidget::uiChanged()
{
    if (rules == nullptr) {
        qDebug() << "uiUpdating default";
        return;
    }

    ((LayoutsTableModel *)ui.layoutsTableView->model())->refresh();
    layoutSelectionChanged();
    // this collapses the tree so use more fine-grained updates
    //	((LayoutsTableModel*)uiWidget->xkbOptionsTreeView->model())->refresh();

    if (uiUpdating) {
        qDebug() << "uiUpdating default";
        return;
    }
    updateXkbShortcutsButtons();
    updateLoopCount();
    int loop = KeyboardConfig::NO_LOOPING;
    keyboardConfig->setLayoutLoopCount(loop);

    layoutsTableModel->refresh();
    layoutSelectionChanged();
    // Refresh layout shortcuts
    switchKeyboardShortcutChanged();

    Q_EMIT changed(true);
}

void KCMiscKeyboardWidget::moveUp()
{
    moveSelectedLayouts(-1);
}

void KCMiscKeyboardWidget::moveDown()
{
    moveSelectedLayouts(1);
}

void KCMiscKeyboardWidget::updateXkbShortcutsButtons()
{

}

void KCMiscKeyboardWidget::previewLayout()
{
    QModelIndex index = ui.layoutsTableView->currentIndex();
    QModelIndex idcountry = index.sibling(index.row(), 0);
    const QString country = ui.layoutsTableView->model()->data(idcountry).toString();
    const QModelIndex idvariant = index.sibling(index.row(), 2);
    QString variant = ui.layoutsTableView->model()->data(idvariant).toString();
    const QString model = keyboardModelFromUI();
    const QStringList options = xkbOptionsFromUI();

    const LayoutInfo *layoutInfo = rules->getLayoutInfo(country);
    if (!layoutInfo) {
        return;
    }
    for (const VariantInfo *variantInfo : layoutInfo->variantInfos) {
        if (variant == variantInfo->description) {
            variant = variantInfo->name;
            break;
        }
    }
    const QString title = Flags::getLongText(LayoutUnit(country, variant), rules);
    Tastenbrett::launch(model, country, variant, options.join(','), title);
}

void KCMiscKeyboardWidget::switchKeyboardShortcutChanged()
{
    if (rules == nullptr) {
        return;
    }
    if (actionCollection == nullptr) {
        actionCollection = new KeyboardLayoutActionCollection(this, true);
    }
    actionCollection->resetLayoutShortcuts();
    actionCollection->setLayoutShortcuts(keyboardConfig->layouts, rules);
}

void KCMiscKeyboardWidget::setDefaultIndicatorVisible(QWidget *widget, bool visible)
{
    widget->setProperty("_kde_highlight_neutral", visible);
    widget->update();
}

void KCMiscKeyboardWidget::moveSelectedLayouts(int shift)
{
    QItemSelectionModel *selectionModel = ui.layoutsTableView->selectionModel();
    if (selectionModel == nullptr || !selectionModel->hasSelection())
        return;

    const QModelIndexList selected = selectionModel->selectedRows();
    if (selected.count() < 1)
        return;

    int newFirstRow = selected[0].row() + shift;
    int newLastRow = selected[selected.size() - 1].row() + shift;

    if (newFirstRow >= 0 && newLastRow <= keyboardConfig->layouts.size() - 1) {
        QList<int> selectionRows;
        for (const QModelIndex &index : selected) {
            int newRowIndex = index.row() + shift;
            keyboardConfig->layouts.move(index.row(), newRowIndex);
            selectionRows << newRowIndex;
        }
        uiChanged();

        QItemSelection selection;
        for (const int row : qAsConst(selectionRows)) {
            QModelIndex topLeft = layoutsTableModel->index(row, 0, QModelIndex());
            QModelIndex bottomRight = layoutsTableModel->index(row, layoutsTableModel->columnCount(topLeft) - 1, QModelIndex());
            selection << QItemSelectionRange(topLeft, bottomRight);
        }
        ui.layoutsTableView->selectionModel()->select(selection, QItemSelectionModel::SelectCurrent);
        ui.layoutsTableView->setFocus();
    }
}

KeyBehaviour KCMiscKeyboardWidget::defaultValueKeyboardRepeat() const
{
    if (m_settings->defaultKeyboardRepeatValue() == keybehaviourNames[KeyBehaviour::AccentMenu] && !hasAccentSupport()) {
        return KeyBehaviour::RepeatKey;
    }

    const auto keys = keybehaviourNames.keys();
    auto defaultRepeat = std::find_if(keys.constBegin(), keys.constEnd(), [=](const KeyBehaviour &key) {
        return keybehaviourNames[key] == m_settings->defaultKeyboardRepeatValue();
    });

    return *defaultRepeat;
}

QString KCMiscKeyboardWidget::keyboardModelFromUI() const
{
    return ui.keyboardModelComboBox->itemData(ui.keyboardModelComboBox->currentIndex()).toString();
}

QStringList KCMiscKeyboardWidget::xkbOptionsFromUI() const
{
    XkbOptionsTreeModel *model = dynamic_cast<XkbOptionsTreeModel *>(ui.xkbOptionsTreeView->model());
    return model->xkbOptions();
}

void KCMiscKeyboardWidget::configureXkbOptionsChanged()
{
    if (ui.kcfg_resetOldXkbOptions->isChecked() && keyboardConfig->xkbOptions().isEmpty()) {
        populateWithCurrentXkbOptions();
    }
    ((XkbOptionsTreeModel *)ui.xkbOptionsTreeView->model())->reset();
    uiChanged();
}

void KCMiscKeyboardWidget::updateXkbShortcutButton(const QString &groupName, QPushButton *button)
{
    QStringList grpOptions;
    if (ui.kcfg_resetOldXkbOptions->isChecked()) {
        QRegularExpression regexp("^" + groupName + Rules::XKB_OPTION_GROUP_SEPARATOR);
        XkbOptionsTreeModel *model = dynamic_cast<XkbOptionsTreeModel *>(ui.xkbOptionsTreeView->model());
        grpOptions = model->xkbOptions().filter(regexp);
    }
    switch (grpOptions.size()) {
    case 0:
        button->setText(i18nc("no shortcuts defined", "None"));
        break;
    case 1: {
        const QString &option = grpOptions.first();
        const OptionGroupInfo *optionGroupInfo = rules->getOptionGroupInfo(groupName);
        const OptionInfo *optionInfo = optionGroupInfo->getOptionInfo(option);
        if (optionInfo == nullptr || optionInfo->description == nullptr) {
            //qCDebug(KCM_KEYBOARD) << "Could not find option info for " << option;
            button->setText(grpOptions.first());
        } else {
            button->setText(optionInfo->description);
        }
    } break;
    default:
        button->setText(i18np("%1 shortcut", "%1 shortcuts", grpOptions.size()));
    }
}

void KCMiscKeyboardWidget::populateWithCurrentXkbOptions()
{
    if (!KWindowSystem::isPlatformX11()) {
        // TODO: implement for Wayland - query dbus maybe?
        return;
    }
    XkbConfig xkbConfig;
    QStringList xkbOptions;
    if (X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::ALL)) {
        xkbOptions = xkbConfig.options;
    }
    auto *xkbOptionModel = dynamic_cast<XkbOptionsTreeModel *>(ui.xkbOptionsTreeView->model());
    xkbOptionModel->setXkbOptions(xkbOptions);
    keyboardConfig->setXkbOptions(xkbOptions);
}

void KCMiscKeyboardWidget::updateLoopCount()
{
//    int maxLoop = qMin(X11Helper::MAX_GROUP_COUNT, keyboardConfig->layouts.count() - 1);
//    ui.layoutLoopCountSpinBox->setMaximum(qMax(MIN_LOOPING_COUNT, maxLoop));

//    if (maxLoop < MIN_LOOPING_COUNT) {
//        ui.layoutLoopingCheckBox->setEnabled(false);
//        ui.layoutLoopingCheckBox->setChecked(false);
//    } else if (maxLoop >= X11Helper::MAX_GROUP_COUNT) {
//        ui.oopingCheckBox->setChecked(true);
//    } else {
//        ui.layoutLoopingCheckBox->setEnabled(keyboardConfig->configureLayouts());
//    }

//    uiWidget->layoutLoopingGroupBox->setEnabled(keyboardConfig->configureLayouts() && uiWidget->layoutLoopingCheckBox->isChecked());

//    if (uiWidget->layoutLoopingCheckBox->isChecked()) {
//        if (ui.layoutLoopCountSpinBox->text().isEmpty()) {
//            ui.>layoutLoopCountSpinBox->setValue(maxLoop);
//            keyboardConfig->setLayoutLoopCount(maxLoop);
//        }
//    } else {
//        ui.layoutLoopCountSpinBox->clear();
//        keyboardConfig->setLayoutLoopCount(KeyboardConfig::NO_LOOPING);
//    }
}

#include "kcmmisc.moc"
